﻿#include "FITKAcousticsVTKGraphObjectSEAJunction.h"
#include "FITKAcousticsVTKGraphActor.h"

// VTK
#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPoints.h>

// App
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"

// Data
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractJunction.h"

// Graph and filter
#include "FITKAcousticsVTKCommons.h"
#include "FITKAcousticsVTKSharedDataManager.h"
#include "FITKAcousticsVTKGraphObjectSelect.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"

namespace Exchange
{
    FITKAcousticsVTKGraphObjectSEAJunction::FITKAcousticsVTKGraphObjectSEAJunction(Acoustics::FITKAbstractJunction* junction)
        : FITKAcousticsVTKGraphObject3D(junction)
    {
        // Set the layer need to be rendered.
        setRenderLayer(0, 2);
    }

    FITKAcousticsVTKGraphObjectSEAJunction::~FITKAcousticsVTKGraphObjectSEAJunction()
    { 
        // Delete vtk objects.
        deleteVtkObj(m_points);
        deleteVtkObj(m_ugrid);  
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::init()
    {
        // Create the grid.
        m_ugrid = vtkUnstructuredGrid::New();
        m_points = vtkPoints::New();
        m_ugrid->SetPoints(m_points);
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::update(bool forceUpdate)
    {
        // Return if the 'forceUpdate' is false.
        Acoustics::FITKAbstractJunction* junction = dynamic_cast<Acoustics::FITKAbstractJunction*>(_dataObj);
        if (!junction)
        {
            return;
        }

        if (!m_ugrid || !m_points)
        {
            return;
        }

        // Update the visibility.
        updateVisibility();

        // Update the glyph size.
        updateGlyphSizeByRatio();

        // Update the color by enabled flag.
        updateColorByEnableFlag();

        if (!forceUpdate)
        {
            return;
        }

        // Reset the data.
        resetVtkData();
        
        // Re-generate the grid data.
        generateDataSet(junction);

        // Update the actors.
        m_ugrid->Modified();
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::highlight(FITKAcousticsVTKCommons::ShapeType type, QColor color)
    {
        // Change the view mode to wireframe.
        if (m_fActor)
        {
            m_fActor->GetProperty()->SetRepresentation(1);
        }

        // Save the highlight flag.
        this->Superclass::highlight(type, color);
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::disHighlight()
    {
        // Change the view mode to surface.
        if (m_fActor)
        {
            m_fActor->GetProperty()->SetRepresentation(2);
        }

        // Save the highlight flag.
        this->Superclass::disHighlight();
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::advanceHighlight(FITKAcousticsVTKCommons::ShapeType type, QVector<int> indice, QColor color)
    {
        // Save the highlight flag.
        this->Superclass::advanceHighlight(type, indice, color);
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::disAdvanceHighlight()
    {
        // Save the highlight flag.
        this->Superclass::disAdvanceHighlight();
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::setPickMode(FITKAcousticsVTKCommons::ShapePickMode mode)
    {
        if (!m_fActor)
        {
            return;
        }

        switch (mode)
        {
        case Exchange::FITKAcousticsVTKCommons::PickAll:
            m_fActor->SetPickable(true);
            break;
        case Exchange::FITKAcousticsVTKCommons::PickNone:
        case Exchange::FITKAcousticsVTKCommons::PickVertex:
        case Exchange::FITKAcousticsVTKCommons::PickEdge:
        case Exchange::FITKAcousticsVTKCommons::PickFace:
        case Exchange::FITKAcousticsVTKCommons::PickSolid:
        case Exchange::FITKAcousticsVTKCommons::PickNode:
        case Exchange::FITKAcousticsVTKCommons::PickElement:     
        default:
            m_fActor->SetPickable(false);
            break;
        }
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::generateGraph()
    {
        // Create grid actor.
        m_fActor = FITKAcousticsVTKGraphActor::New();
        m_fActor->setGraphObject(this);
        m_fActor->setActorType(ActorType::SurfaceActor);
        m_fActor->SetPickable(false);
        m_fActor->SetVisibility(true);
        m_fActor->GetProperty()->SetRepresentation(2);
        m_fActor->GetProperty()->SetPointSize(0.);
        m_fActor->GetProperty()->SetLineWidth(1.);
        m_fActor->setRelativeCoincidentTopologyPolygonOffsetParameters(m_polygonOffset);
        addActor(m_fActor);

        // Set the input data.
        m_fActor->setInputDataObject(m_ugrid);

        // Initialize color.
        Acoustics::FITKAbstractJunction* junction = dynamic_cast<Acoustics::FITKAbstractJunction*>(_dataObj);
        if (!junction)
        {
            return;
        }

        // Update the color by the enabled flag.
        updateColorByEnableFlag();
    }

    Acoustics::FITKAcousticsDiscNodeList* FITKAcousticsVTKGraphObjectSEAJunction::getSEANodesData()
    {
        // Get the SEA-model data.
        Acoustics::FITKAcousticsDiscModel* discModel = FITKGLODATA->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel)
        {
            return nullptr;
        }

        Acoustics::FITKAcousticsSEAModel* seaModel = discModel->getSEAModel();
        if (!seaModel)
        {
            return nullptr;
        }

        // Get the SEA nodes.
        Acoustics::FITKAcousticsDiscNodeList* seaNodes = discModel->getNodes();
        if (!seaNodes)
        {
            return nullptr;
        }

        return seaNodes;
    }

    vtkDataSet* FITKAcousticsVTKGraphObjectSEAJunction::getMesh(FITKAcousticsVTKCommons::ShapeType type)
    {
        Q_UNUSED(type);
        return m_ugrid;
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::resetVtkData()
    {
        resetVtkObj(m_points);
        resetVtkObj(m_ugrid);
    }

    void FITKAcousticsVTKGraphObjectSEAJunction::updateColorByEnableFlag()
    {
        Acoustics::FITKAbstractJunction* junction = dynamic_cast<Acoustics::FITKAbstractJunction*>(_dataObj);
        if (!junction)
        {
            return;
        }

        double color3[3]{ 0., 0., 0. };
        if (junction->getEnabledJunction())
        {
            FITKAcousticsVTKCommons::QColorToDouble3(FITKAcousticsVTKCommons::s_SEAJunctionEnabledColor, color3);
        }
        else
        {
            FITKAcousticsVTKCommons::QColorToDouble3(FITKAcousticsVTKCommons::s_SEAJunctionDisabledColor, color3);
        }

        for (vtkProp* prop : m_actorList)
        {
            FITKAcousticsVTKGraphActor* fActor = FITKAcousticsVTKGraphActor::SafeDownCast(prop);
            if (fActor)
            {
                fActor->GetProperty()->SetColor(color3);
            }
        }
    }

    bool FITKAcousticsVTKGraphObjectSEAJunction::getGlobalSEAJunctionsVisibility()
    {
        // Get the runtime settings for visibility. 
        bool showJunctions = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_JUNCTIONS, true);
        return showJunctions;
    }
}   // namespace Exchange